// Decompiled on 周六 2月 22 19:31:49 CST 2025 with Zomboid Decompiler v0.1.3 using Vineflower.
package zombie;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.TreeMap;
import zombie.characters.IsoGameCharacter;
import zombie.characters.IsoZombie;
import zombie.characters.ZombiesZoneDefinition;
import zombie.characters.AttachedItems.AttachedWeaponDefinitions;
import zombie.core.Core;
import zombie.core.Rand;
import zombie.core.logger.ExceptionLogger;
import zombie.core.skinnedmodel.population.Outfit;
import zombie.core.skinnedmodel.population.OutfitManager;
import zombie.core.skinnedmodel.population.OutfitRNG;
import zombie.core.skinnedmodel.visual.ItemVisual;
import zombie.core.skinnedmodel.visual.ItemVisuals;
import zombie.iso.IsoWorld;
import zombie.iso.SliceY;
import zombie.network.GameClient;
import zombie.network.GameServer;
import zombie.randomizedWorld.randomizedVehicleStory.RandomizedVehicleStoryBase;
import zombie.scripting.objects.Item;
import zombie.util.Type;
import zombie.util.list.PZArrayUtil;

public class PersistentOutfits {
    public static final zombie.PersistentOutfits instance = new zombie.PersistentOutfits();
    public static final int INVALID_ID = 0;
    public static final int FEMALE_BIT = Integer.MIN_VALUE;
    public static final int NO_HAT_BIT = 32768;
    private static final int FILE_VERSION_1 = 1;
    private static final int FILE_VERSION_LATEST = 1;
    private static final byte[] FILE_MAGIC = new byte[]{80, 83, 84, 90};
    private static final int NUM_SEEDS = 500;
    private final long[] m_seeds = new long[500];
    private final ArrayList<String> m_outfitNames = new ArrayList();
    private final zombie.PersistentOutfits.DataList m_all = new zombie.PersistentOutfits.DataList();
    private final zombie.PersistentOutfits.DataList m_female = new zombie.PersistentOutfits.DataList();
    private final zombie.PersistentOutfits.DataList m_male = new zombie.PersistentOutfits.DataList();
    private final TreeMap<String, zombie.PersistentOutfits.Data> m_outfitToData = new TreeMap(String.CASE_INSENSITIVE_ORDER);
    private final TreeMap<String, zombie.PersistentOutfits.Data> m_outfitToFemale = new TreeMap(String.CASE_INSENSITIVE_ORDER);
    private final TreeMap<String, zombie.PersistentOutfits.Data> m_outfitToMale = new TreeMap(String.CASE_INSENSITIVE_ORDER);
    private static final ItemVisuals tempItemVisuals = new ItemVisuals();

    public void init() {
        this.m_all.clear();
        this.m_female.clear();
        this.m_male.clear();
        this.m_outfitToData.clear();
        this.m_outfitToFemale.clear();
        this.m_outfitToMale.clear();
        this.m_outfitNames.clear();
        if (!GameClient.bClient) {
            for (int _int = 0; _int < 500; _int++) {
                this.m_seeds[_int] = (long)Rand.Next(Integer.MAX_VALUE);
            }
        }

        this.initOutfitList(OutfitManager.instance.m_FemaleOutfits, true);
        this.initOutfitList(OutfitManager.instance.m_MaleOutfits, false);
        this.registerCustomOutfits();
        if (!GameClient.bClient) {
            this.load();
            this.save();
        }
    }

    private void initOutfitList(ArrayList<Outfit> arrayList1, boolean _boolean) {
        ArrayList arrayList0 = new ArrayList(arrayList1);
        arrayList0.sort((outfit1, outfit0) -> outfit1.m_Name.compareTo(outfit0.m_Name));

        for (Outfit outfit : arrayList0) {
            this.initOutfit(outfit.m_Name, _boolean, true, zombie.PersistentOutfits::ApplyOutfit);
        }
    }

    private void initOutfit(String string, boolean boolean0, boolean boolean1, zombie.PersistentOutfits.IOutfitter iOutfitter) {
        TreeMap treeMap = boolean0 ? this.m_outfitToFemale : this.m_outfitToMale;
        zombie.PersistentOutfits.Data data = (zombie.PersistentOutfits.Data)this.m_outfitToData.get(string);
        if (data == null) {
            data = new zombie.PersistentOutfits.Data();
            data.m_index = (short)this.m_all.size();
            data.m_outfitName = string;
            data.m_useSeed = boolean1;
            data.m_outfitter = iOutfitter;
            this.m_outfitNames.add(string);
            this.m_outfitToData.put(string, data);
            this.m_all.add(data);
        }

        zombie.PersistentOutfits.DataList dataList = boolean0 ? this.m_female : this.m_male;
        dataList.add(data);
        treeMap.put(string, data);
    }

    private void registerCustomOutfits() {
        ArrayList arrayList = IsoWorld.instance.getRandomizedVehicleStoryList();

        for (int _int = 0; _int < arrayList.size(); _int++) {
            RandomizedVehicleStoryBase randomizedVehicleStoryBase = (RandomizedVehicleStoryBase)arrayList.get(_int);
            randomizedVehicleStoryBase.registerCustomOutfits();
        }

        ZombiesZoneDefinition.registerCustomOutfits();
        if (GameServer.bServer || GameClient.bClient) {
            this.registerOutfitter("ReanimatedPlayer", false, zombie.SharedDescriptors::ApplyReanimatedPlayerOutfit);
        }
    }

    public ArrayList<String> getOutfitNames() {
        return this.m_outfitNames;
    }

    public int pickRandomFemale() {
        if (this.m_female.isEmpty()) {
            return 0;
        } else {
            String string = PZArrayUtil.pickRandom(this.m_female).m_outfitName;
            return this.pickOutfitFemale(string);
        }
    }

    public int pickRandomMale() {
        if (this.m_male.isEmpty()) {
            return 0;
        } else {
            String string = PZArrayUtil.pickRandom(this.m_male).m_outfitName;
            return this.pickOutfitMale(string);
        }
    }

    public int pickOutfitFemale(String outfitName) {
        zombie.PersistentOutfits.Data data = (zombie.PersistentOutfits.Data)this.m_outfitToFemale.get(outfitName);
        if (data == null) {
            return 0;
        } else {
            short short0 = (short)data.m_index;
            short short1 = data.m_useSeed ? (short)Rand.Next(500) : 0;
            return -2147483648 | short0 << 16 | short1 + 1;
        }
    }

    public int pickOutfitMale(String outfitName) {
        zombie.PersistentOutfits.Data data = (zombie.PersistentOutfits.Data)this.m_outfitToMale.get(outfitName);
        if (data == null) {
            return 0;
        } else {
            short short0 = (short)data.m_index;
            short short1 = data.m_useSeed ? (short)Rand.Next(500) : 0;
            return short0 << 16 | short1 + 1;
        }
    }

    public int pickOutfit(String outfitName, boolean female) {
        return female ? this.pickOutfitFemale(outfitName) : this.pickOutfitMale(outfitName);
    }

    public int getOutfit(int ID) {
        if (ID == 0) {
            return 0;
        } else {
            int int0 = ID & -2147483648;
            ID &= Integer.MAX_VALUE;
            int int1 = ID & 32768;
            ID &= -32769;
            short short0 = (short)(ID >> 16);
            short short1 = (short)(ID & 65535);
            if (short0 >= 0 && short0 < this.m_all.size()) {
                zombie.PersistentOutfits.Data data = (zombie.PersistentOutfits.Data)this.m_all.get(short0);
                if (data.m_useSeed && (short1 < 1 || short1 > 500)) {
                    short1 = (short)(Rand.Next(500) + 1);
                }

                return int0 | int1 | short0 << 16 | short1;
            } else {
                return 0;
            }
        }
    }

    public void save() {
        if (!Core.getInstance().isNoSave()) {
            File file = zombie.ZomboidFileSystem.instance.getFileInCurrentSave("z_outfits.bin");

            try {
                FileOutputStream fileOutputStream = new FileOutputStream(file);

                try {
                    BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);

                    try {
                        synchronized (SliceY.SliceBufferLock) {
                            SliceY.SliceBuffer.clear();
                            ByteBuffer byteBuffer = SliceY.SliceBuffer;
                            this.save(byteBuffer);
                            bufferedOutputStream.write(byteBuffer.array(), 0, byteBuffer.position());
                        }
                    } catch (Throwable throwable0) {
                        try {
                            bufferedOutputStream.close();
                        } catch (Throwable throwable1) {
                            throwable0.addSuppressed(throwable1);
                        }

                        throw throwable0;
                    }

                    bufferedOutputStream.close();
                } catch (Throwable throwable2) {
                    try {
                        fileOutputStream.close();
                    } catch (Throwable throwable3) {
                        throwable2.addSuppressed(throwable3);
                    }

                    throw throwable2;
                }

                fileOutputStream.close();
            } catch (Exception exception) {
                ExceptionLogger.logException(exception);
            }
        }
    }

    public void save(ByteBuffer output) {
        output.put(FILE_MAGIC);
        output.putInt(1);
        output.putShort((short)500);

        for (int _int = 0; _int < 500; _int++) {
            output.putLong(this.m_seeds[_int]);
        }
    }

    public void load() {
        File file = zombie.ZomboidFileSystem.instance.getFileInCurrentSave("z_outfits.bin");

        try {
            FileInputStream fileInputStream = new FileInputStream(file);

            try {
                BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);

                try {
                    synchronized (SliceY.SliceBufferLock) {
                        SliceY.SliceBuffer.clear();
                        ByteBuffer byteBuffer = SliceY.SliceBuffer;
                        int _int = bufferedInputStream.read(byteBuffer.array());
                        byteBuffer.limit(_int);
                        this.load(byteBuffer);
                    }
                } catch (Throwable throwable0) {
                    try {
                        bufferedInputStream.close();
                    } catch (Throwable throwable1) {
                        throwable0.addSuppressed(throwable1);
                    }

                    throw throwable0;
                }

                bufferedInputStream.close();
            } catch (Throwable throwable2) {
                try {
                    fileInputStream.close();
                } catch (Throwable throwable3) {
                    throwable2.addSuppressed(throwable3);
                }

                throw throwable2;
            }

            fileInputStream.close();
        } catch (FileNotFoundException fileNotFoundException) {
        } catch (Exception exception) {
            ExceptionLogger.logException(exception);
        }
    }

    public void load(ByteBuffer input) throws IOException {
        byte[] _byte = new byte[4];
        input.get(_byte);
        if (!Arrays.equals(_byte, FILE_MAGIC)) {
            throw new IOException("not magic");
        } else {
            int int0 = input.getInt();
            if (int0 >= 1 && int0 <= 1) {
                short _short = input.getShort();

                for (int int1 = 0; int1 < _short; int1++) {
                    if (int1 < 500) {
                        this.m_seeds[int1] = input.getLong();
                    }
                }
            }
        }
    }

    public void registerOutfitter(String id, boolean useSeed, zombie.PersistentOutfits.IOutfitter outfitter) {
        this.initOutfit(id, true, useSeed, outfitter);
        this.initOutfit(id, false, useSeed, outfitter);
    }

    private static void ApplyOutfit(int _int, String string, IsoGameCharacter isoGameCharacter) {
        instance.applyOutfit(_int, string, isoGameCharacter);
    }

    private void applyOutfit(int _int, String var2, IsoGameCharacter isoGameCharacter) {
        boolean _boolean = (_int & -2147483648) != 0;
        _int &= Integer.MAX_VALUE;
        short _short = (short)(_int >> 16);
        zombie.PersistentOutfits.Data data = (zombie.PersistentOutfits.Data)this.m_all.get(_short);
        IsoZombie isoZombie = Type.tryCastTo(isoGameCharacter, IsoZombie.class);
        if (isoZombie != null) {
            isoZombie.setFemaleEtc(_boolean);
        }

        isoGameCharacter.dressInNamedOutfit(data.m_outfitName);
        if (isoZombie != null && isoGameCharacter.doDirtBloodEtc) {
            AttachedWeaponDefinitions.instance.addRandomAttachedWeapon(isoZombie);
            isoZombie.addRandomBloodDirtHolesEtc();
        }

        this.removeFallenHat(_int, isoGameCharacter);
    }

    public boolean isHatFallen(IsoGameCharacter chr) {
        return this.isHatFallen(chr.getPersistentOutfitID());
    }

    public boolean isHatFallen(int outfitID) {
        return (outfitID & 32768) != 0;
    }

    public void setFallenHat(IsoGameCharacter chr, boolean fallen) {
        int _int = chr.getPersistentOutfitID();
        if (_int != 0) {
            if (fallen) {
                _int |= 32768;
            } else {
                _int &= -32769;
            }

            chr.setPersistentOutfitID(_int, chr.isPersistentOutfitInit());
        }
    }

    public boolean removeFallenHat(int outfitID, IsoGameCharacter chr) {
        if ((outfitID & 32768) == 0) {
            return false;
        } else if (chr.isUsingWornItems()) {
            return false;
        } else {
            boolean _boolean = false;
            chr.getItemVisuals(tempItemVisuals);

            for (int _int = 0; _int < tempItemVisuals.size(); _int++) {
                ItemVisual itemVisual = (ItemVisual)tempItemVisuals.get(_int);
                Item item = itemVisual.getScriptItem();
                if (item != null && item.getChanceToFall() > 0) {
                    chr.getItemVisuals().remove(itemVisual);
                    _boolean = true;
                }
            }

            return _boolean;
        }
    }

    public void dressInOutfit(IsoGameCharacter chr, int outfitID) {
        outfitID = this.getOutfit(outfitID);
        if (outfitID != 0) {
            int _int = outfitID & 2147450879;
            short short0 = (short)(_int >> 16);
            short short1 = (short)(_int & 65535);
            zombie.PersistentOutfits.Data data = (zombie.PersistentOutfits.Data)this.m_all.get(short0);
            if (data.m_useSeed) {
                OutfitRNG.setSeed(this.m_seeds[short1 - 1]);
            }

            data.m_outfitter.accept(outfitID, data.m_outfitName, chr);
        }
    }

    private static final class Data {
        int m_index;
        String m_outfitName;
        boolean m_useSeed = true;
        zombie.PersistentOutfits.IOutfitter m_outfitter;
    }

    private static final class DataList extends ArrayList<zombie.PersistentOutfits.Data> {
    }

    public interface IOutfitter {
        void accept(int outfitID, String outfitName, IsoGameCharacter chr);
    }
}
